﻿using BtLabelModel;
using Gma.QrCodeNet.Encoding;
using Gma.QrCodeNet.Encoding.Windows.Render;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;


namespace BtLabelBLL
{
    class ProductBLL
    {
        /// <summary>
        /// 白，黑，红
        /// </summary>
        private static int[,] colors = new int[3, 3]
            {
                    {0,0,0},
                    {255,255,255},
                    {255,0,0}
            };
        /// <summary>
        /// 颜色算法
        /// </summary>
        /// <param name="r"></param>
        /// <param name="g"></param>
        /// <param name="b"></param>
        /// <param name="index"></param>
        /// <returns></returns>
        private static int getErr(int r, int g, int b, int index)
        {
            int rd, gd, bd;
            rd = r - colors[index, 0];
            gd = g - colors[index, 1];
            bd = b - colors[index, 2];

            return rd * rd + bd * bd + gd * gd;
        }
        /// <summary>
        /// 颜色算法得到红黑白三种
        /// </summary>
        /// <param name="r"></param>
        /// <param name="g"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        private static int getNeerColorIndex(int r, int g, int b)
        {
            int index = 0, i = 0;
            int ba = getErr(r, g, b, i);
            for (i = 1; i < 3; i++)
            {
                int temp = getErr(r, g, b, i);
                if (temp < ba)
                {
                    ba = temp;
                    index = i;
                }
            }
            return index;
        }
        /// <summary>
        /// 颜色算法
        /// </summary>
        /// <param name="mDataArray"></param>
        /// <returns></returns>
        private static byte[] CreateRgbData(byte[] mDataArray)
        {
            List<byte> RgbList = new List<byte>();
            for (int i = 0; i < mDataArray.Length; i = i + 8)
            {
                byte first = mDataArray[i];
                for (int j = 1; j < 8; j++)
                {
                    byte second = (byte)((first << 1) | mDataArray[i + j]);
                    first = second;
                }
                RgbList.Add(first);
            }
            return RgbList.ToArray();
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="bmpOriginal"></param>
        /// <param name="width"></param>
        /// <param name="height"></param>
        /// <param name="color">1、black;2、red</param>
        /// <returns></returns>
        public static byte[] BitmapArgbToByte(Bitmap bmpOriginal, int width, int height, int color)
        {
            int k = 0;
            List<byte> rgbByte = new List<byte>();
            try
            {
                for (int x = 0; x < height; x++)
                {
                    for (int y = 0; y < width; y++, k++)
                    {
                        // get one pixel color
                        var rgb = bmpOriginal.GetPixel(y, x);

                        // retrieve color of all channels
                        if (getNeerColorIndex(rgb.R, rgb.G, rgb.B) == color)
                        {
                            rgbByte.Add(1);
                        }
                        else
                        {
                            rgbByte.Add(0);
                        }
                    }
                }
                return CreateRgbData(rgbByte.ToArray());
            }
            catch (Exception ex)
            {
                // TODO: handle exception
                throw ex;
            }
        }
        /// <summary>
        /// 生成二维码图片
        /// </summary>
        /// <param name="content"></param>
        /// <param name="fileName"></param>
        public static void CreateQrCode(String content, String fileName)
        {
            try
            {
                //生成二维码
                QrEncoder qrEncoder = new QrEncoder(ErrorCorrectionLevel.M);
                QrCode qrCode = qrEncoder.Encode(content.Replace(" ",""));
                GraphicsRenderer render = new GraphicsRenderer(new FixedModuleSize(20, QuietZoneModules.Two), Brushes.Black, Brushes.White);
                using (FileStream stream = new FileStream(fileName, FileMode.Create))
                {
                    render.WriteToStream(qrCode.Matrix, ImageFormat.Png, stream);
                    stream.Close();
                }
                //加入文字
                Font font = new Font("微软雅黑", 20, FontStyle.Regular);//设置字体，大小，粗细
                SolidBrush sbrush = new SolidBrush(Color.Red);//设置颜色
                Bitmap im = new Bitmap(fileName);
                Bitmap bmp = new Bitmap(296, 152); //定义图片大小
                Graphics g = Graphics.FromImage(bmp);
                g.Clear(Color.White);
                g.DrawString(content, font, sbrush, new PointF((float)25.4, 118));
                // 合并位图
                g.DrawImage(im, new Rectangle(75, 0, 145, 124));
                im.Dispose();
                bmp.Save(fileName, System.Drawing.Imaging.ImageFormat.Png);
                g.Dispose();
                bmp.Dispose();
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        /// <summary>
        /// 压缩包
        /// </summary>
        /// <param name="inp"></param>
        /// <param name="in_len"></param>
        /// <param name="dict"></param>
        /// <returns></returns>
        public static byte[] data_do_compress(byte[] inp, int in_len, int[] dict)
        {
            int out_len = 0;
            byte[] outp = new byte[4800];
            var ip = 0;
            var in_base = 0;
            var out_base = 0;
            var in_end = in_base + in_len;
            var ip_end = in_base + in_len - 8 - 5;
            var ii = 0;
            var state = 1;
            var op = out_base;
            ii = in_base;
            ip = in_base + 4;
            var m_pos = in_base;
            var m_off = in_base;
            var m_len = 0;
            var dindex = 0;

            //label176:
            while (true)
            {
                //label174:
                while (true)
                {
                    while (true)
                    {
                        while (true)
                        {
                            //label168:
                            {
                                //label167:
                                while (true)
                                {
                                    switch (state)
                                    {
                                        case 1:
                                            dindex = (33 * (((inp[ip + 1 + 2 + 1] & 255) << 6 ^ (inp[ip + 1 + 1 + 1] & 255) << 5 ^ (inp[ip + 1 + 0] & 255) << 5 ^ inp[ip + 0] & 255) >> 5) & 16383) << 0;
                                            m_pos = dict[dindex];
                                            m_pos = ip - (ip - m_pos);
                                            if (m_pos > in_base && (m_off = ip - m_pos) > 0 && m_off <= 49151)
                                            {
                                                if (m_off > 2048 && inp[m_pos + 3] != inp[ip + 3])
                                                {
                                                    dindex = dindex & 2047 ^ 8223;
                                                    m_pos = dict[dindex];
                                                    if (m_pos >= in_base && (m_off = ip - m_pos) > 0 && m_off <= 49151)
                                                    {
                                                        if (m_off > 2048 && inp[m_pos + 3] != inp[ip + 3])
                                                        {
                                                            state = 3;
                                                        }
                                                        else
                                                        {
                                                            state = 2;
                                                        }
                                                    }
                                                    else
                                                    {
                                                        state = 3;
                                                    }
                                                }
                                                else
                                                {
                                                    state = 2;
                                                }
                                            }
                                            else
                                            {
                                                state = 3;
                                            }
                                            break;
                                        case 2:
                                            if (inp[m_pos] == inp[ip] && inp[m_pos + 1] == inp[ip + 1] && inp[m_pos + 2] == inp[ip + 2])
                                            {
                                                state = 4;
                                                break;
                                            }
                                            goto label3;
                                        //break label174;
                                        case 3:
                                            goto label3;
                                        //break label174;
                                        case 4:
                                            dict[dindex] = ip;
                                            int end;
                                            int tt;
                                            if (ip - ii > 0)
                                            {
                                                end = ip - ii;
                                                if (end <= 3)
                                                {
                                                    outp[op - 2] |= (byte)(end & 0xFF);
                                                }
                                                else if (end <= 18)
                                                {
                                                    outp[op++] = (byte)((end - 3) & 0xFF);
                                                }
                                                else
                                                {
                                                    tt = end - 18;

                                                    for (outp[op++] = 0; tt > 255; outp[op++] = 0)
                                                    {
                                                        tt -= 255;
                                                    }

                                                    outp[op++] = (byte)(tt & 0xFF);
                                                }

                                                do
                                                {
                                                    outp[op++] = inp[ii++];
                                                    --end;
                                                } while (end > 0);
                                            }

                                            ip += 3;
                                            if (inp[m_pos + 3] == inp[ip++] && inp[m_pos + 4] == inp[ip++] && inp[m_pos + 5] == inp[ip++] && inp[m_pos + 6] == inp[ip++] && inp[m_pos + 7] == inp[ip++] && inp[m_pos + 8] == inp[ip++])
                                            {
                                                end = in_end;

                                                for (tt = m_pos + 8 + 1; ip < end && inp[tt] == inp[ip]; ++ip)
                                                {
                                                    ++tt;
                                                }

                                                m_len = ip - ii;
                                                if (m_off <= 16384)
                                                {
                                                    --m_off;
                                                    if (m_len > 33)
                                                    {
                                                        m_len -= 33;
                                                        outp[op++] = 32;
                                                        state = 5;
                                                        break;
                                                    }

                                                    outp[op++] = (byte)((32 | m_len - 2) & 0xFF);
                                                }
                                                else
                                                {
                                                    m_off -= 16384;
                                                    if (m_len <= 9)
                                                    {
                                                        outp[op++] = (byte)((16 | (m_off & 16384) >> 11 | m_len - 2) & 0xFF);
                                                    }
                                                    else
                                                    {
                                                        m_len -= 9;

                                                        for (outp[op++] = (byte)((16 | (m_off & 16384) >> 11) & 0xFF); m_len > 255; outp[op++] = 0)
                                                        {
                                                            m_len -= 255;
                                                        }

                                                        outp[op++] = (byte)(m_len & 0xFF);
                                                    }
                                                }

                                                outp[op++] = (byte)(((m_off & 63) << 2) & 0xFF);
                                                outp[op++] = (byte)((m_off >> 6) & 0xFF);
                                                state = 7;
                                            }
                                            else
                                            {
                                                --ip;
                                                m_len = ip - ii;
                                                if (m_off <= 2048)
                                                {
                                                    --m_off;
                                                    outp[op++] = (byte)((m_len - 1 << 5 | (m_off & 7) << 2) & 0xFF);
                                                    outp[op++] = (byte)((m_off >> 3) & 0xFF);
                                                    state = 7;
                                                }
                                                else if (m_off <= 16384)
                                                {
                                                    --m_off;
                                                    outp[op++] = (byte)((32 | m_len - 2) & 0xFF);
                                                    state = 6;
                                                }
                                                else
                                                {
                                                    m_off -= 16384;
                                                    outp[op++] = (byte)((16 | (m_off & 16384) >> 11 | m_len - 2) & 0xFF);
                                                    state = 6;
                                                }
                                            }
                                            break;
                                        case 5:
                                            while (m_len > 255)
                                            {
                                                m_len -= 255;
                                                outp[op++] = 0;
                                            }
                                            outp[op++] = (byte)(m_len & 0xFF);
                                            goto label1;
                                        //break label167;
                                        case 6:
                                            goto label1;
                                        //break label167;
                                        case 7:
                                            goto label2;
                                            //break label168;
                                    }
                                }
                            label1:
                                outp[op++] = (byte)(((m_off & 63) << 2) & 0xFF);
                                outp[op++] = (byte)((m_off >> 6) & 0xFF);
                            }
                        label2:
                            ii = ip;
                            if (ip >= ip_end)
                            {
                                goto label4;
                                //break label176;
                            }
                            state = 1;
                        }
                    }
                }
            label3:
                dict[dindex] = ip++;
                if (ip >= ip_end)
                {
                    break;
                }
                state = 1;
            }
        label4:
            out_len = op - out_base;
            {
                in_base = 0;
                out_base = 0;
                op = 0;
                int t = 0;
                if (in_len <= 13)
                {
                    t = in_len;
                }
                else
                {
                    t = in_end - ii;
                    op += out_len;
                }
                if (t > 0)
                {
                    ii = in_base + in_len - t;
                    if (op == out_base && t <= 238)
                    {
                        outp[op++] = (byte)((17 + t) & 0xFF);
                    }
                    else if (t <= 3)
                    {
                        outp[op - 2] |= (byte)(t & 0xFF);
                    }
                    else if (t <= 18)
                    {
                        outp[op++] = (byte)((t - 3) & 0xFF);
                    }
                    else
                    {
                        var tt = t - 18;

                        for (outp[op++] = 0; tt > 255; outp[op++] = 0)
                        {
                            tt -= 255;
                        }
                        outp[op++] = (byte)(tt & 0xFF);
                    }
                    do
                    {
                        outp[op++] = inp[ii++];
                        --t;
                    } while (t > 0);
                }
                outp[op++] = 17;
                outp[op++] = 0;
                outp[op++] = 0;
                out_len = op - out_base;
            }
            return outp.Take(out_len).ToArray();
        }
        /// <summary>
        /// 得到发送数据包
        /// </summary>
        /// <param name="inp"></param>
        /// <returns></returns>
        public static List<JsonModel.BarModel> GetCompressData(byte[] inp)
        {
            List<JsonModel.BarModel> barModels = new List<JsonModel.BarModel>();
            int[] dict = new int[4800 + 61440];
            if (inp.Length > 4800)
            {
                for (int i = 0; (i + 1) * 4800 < inp.Length; i++)
                {
                    JsonModel.BarModel barModel = new JsonModel.BarModel();
                    byte[] bt = data_do_compress(inp.Skip(i*4800).Take(4800).ToArray(), 4800, dict);
                    barModel.CompressByte = bt;
                    barModel.oldLen = 4800;
                    barModels.Add(barModel);

                }
                if (barModels.Count * 4800 < inp.Length)
                {
                    JsonModel.BarModel barModel = new JsonModel.BarModel();
                    byte[] bt = inp.Skip(barModels.Count * 4800).ToArray();
                    barModel.CompressByte = data_do_compress(bt, bt.Length, dict);
                    barModel.oldLen = bt.Length;
                    barModels.Add(barModel);
                }
            }
            else
            {
                JsonModel.BarModel barModel = new JsonModel.BarModel();
                byte[] bt = data_do_compress(inp, inp.Length, dict);
                barModel.CompressByte = bt;
                barModel.oldLen = inp.Length;
                barModels.Add(barModel);
            }
            return barModels;
        }
    }
}
